<template>
  <table v-show="currentPrometheusServer != null" width="100%">
    <tr>
      <td style="width: 150px">Prometheus Sources:</td>
      <td style="width: 150px" align="left">
        <el-select
          v-if="currentPrometheusServer"
          v-model="currentPrometheusServerLabel"
          filterable
          @change="handlePrometheusChange"
        >
          <el-option
            v-for="value in prometheusServers"
            :key="value.namespace + '.' + value.name"
            :label="value.namespace + '.' + value.name"
            :value="value.namespace + '.' + value.name"
          />
        </el-select>
      </td>
      <td style="width: 150px">time range select:</td>
      <td style="width: 150px" align="left">
        <el-select
          v-if="currentPrometheusServer"
          v-model="uiOptions.selectedTimeLabel"
          filterable
          @change="handleSelectTime"
        >
          <el-option
            v-for="value in times"
            :key="value.secs"
            :label="value.label"
            :value="value.label"
          />
        </el-select>
      </td>
      <td style="width: 150px">refresh interval:</td>
      <td style="width: 150px" align="left">
        <el-select
          v-if="currentPrometheusServer"
          v-model="refresh_interval"
          filterable
          @change="handleSelectRefreshInterval"
        >
          <el-option
            v-for="value in refresh_intervals"
            :key="value.refresh_interval"
            :label="value.label"
            :value="value.refresh_interval"
          />
        </el-select>
      </td>
      <td style="width: 150px">
        <el-button type="primary" size="small" @click="loadMetrics"
          >Refresh</el-button
        >
      </td>
      <td style="width: (100%-1050px)" />
    </tr>
    <tr>
      <td colspan="8">
        <div class="Echarts">
          <div :id="uiOptions.chartId" style="width: 100%; height: 300px" />
        </div>
      </td>
    </tr>
  </table>
</template>
<script setup lang="ts">
/*检查已安装在k8s集群中prometheus的服务端*/
// import { listCustomResourceDefinitions } from "@/api/customresourcedefinitions";
// import {
//   listPrometheuses,
//   getContainerMetricsMemAndFs,
//   getContainerMetricsCpu
// } from "@/api/crds/monitoring.coreos.com/v1/prometheus";
/*用户检查prometheus使用的service*/
// import { listServicesWithNs } from "@/api/services";
import moment from "moment";
import { Container, useK8SApi } from "../../../api/k8s";
import { onMounted, onUnmounted, reactive, ref, watch } from "vue";
import { objectToString } from "../../../utils";
import { init as echartInit } from "echarts/core";

const arrayDuplicateRemovalSort = (arr1, arr2) => {
  const arr = arr1.concat(arr2);
  return [...new Set(arr.sort((a, b) => (a > b ? 1 : -1)))];
};

const { metric, serviceRepo, relayServer } = useK8SApi();
type Prop = {
  cluster?: string;
  containerInfo?: Container;
  yamlInfo?: any;
};

const props = defineProps<Prop>();

const loading = ref(false);
type PrometheusServer = {
  name?: string;
  namespace?: string;
  service?: string;
  service_port?: number;
  prefix?: string;
};
const prometheusServers = ref<PrometheusServer[]>([]);
const currentPrometheusServer = ref<PrometheusServer>(null);
const currentPrometheusServerLabel = ref(null);

const uiOptions = reactive({
  myChart: null,
  intervalId: null,
  secs: 1000,
  time_interval: 1,
  selectedTimeLabel: "Half Hour ago",
  selectedTime: null,
  chartId:
    props.cluster +
    "|" +
    (props.yamlInfo?.metadata?.namespace ?? "") +
    "|" +
    (props.yamlInfo?.metadata?.name ?? "") +
    "|" +
    (props.containerInfo?.name ?? "")
});

const times = ref([
  {
    label: "Half Hour ago",
    secs: 1800 /*半小时*/,
    time_interval: 1
  },
  {
    label: "1 Hour ago",
    secs: 3600 /*1小时*/,
    time_interval: 2
  },
  {
    label: "12 Hour ago",
    secs: 3600 * 12 /*12小时*/,
    time_interval: 24
  },
  {
    label: "24 Hour ago",
    secs: 3600 * 24 /*24小时*/,
    time_interval: 48
  }
]);
const refresh_interval = ref(60000); /*一分钟*/
const refresh_intervals = [
  {
    refresh_interval: -1 /*不自动刷新*/,
    label: "no auto refresh"
  },
  {
    refresh_interval: 60000 /*1分钟*/,
    label: "1 Minutes"
  },
  {
    refresh_interval: 300000 /*5分钟*/,
    label: "5 Minutes"
  },
  {
    refresh_interval: 600000 /*10分钟*/,
    label: "10 Minutes"
  }
];

const loadPrometheuses = async () => {
  const crds = await relayServer.listCustomResourceDefinitions(props.cluster);
  const crd = crds?.items.find(
    item => item.metadata.name === "prometheuses.monitoring.coreos.com"
  );
  let prometheusRes = { items: [] };
  if (crd) {
    metric.listPrometheuses(props.cluster).then(({ ok, items }) => {
      if (ok) {
        prometheusRes.items = items;
      }
    });
  }

  if (prometheusRes.items && prometheusRes.items.length > 0) {
    // TODO: 缺少类型定义
    prometheusRes.items.forEach(async item => {
      const svrList = await serviceRepo.getService({
        namespace: item.metadata.namespace,
        labelSelector: objectToString({ prometheus: item.metadata.name })
      });

      const svr = svrList.items?.find(
        item => item.spec.selector["prometheus"] === item.metadata.name
      );

      if (svr) {
        prometheusServers.value.push({
          name: item.metadata.name,
          namespace: item.metadata.namespace,
          service: svr.metadata.name,
          service_port:
            svr.spec?.ports && svr.spec.ports.length > 0
              ? svr.spec.ports[0].port
              : 80,
          prefix: item.spec.routePrefix
        });
      }
    });

    if (prometheusServers.value.length > 0) {
      currentPrometheusServer.value = prometheusServers.value[0];
      currentPrometheusServerLabel.value =
        currentPrometheusServer.value.namespace +
        "." +
        currentPrometheusServer.value.name;
    }
  }
};

const handlePrometheusChange = async value => {
  currentPrometheusServer.value = prometheusServers.value.find(
    row => value === row.namespace + "." + row.name
  );

  if (currentPrometheusServer.value) {
    stopTimeTick();
    loadMetrics();
    startTimeTick();
  }
};

const handleSelectTime = async value => {
  uiOptions.selectedTime = times.value.find(tm => tm.label === value);
  uiOptions.secs = uiOptions.selectedTime.secs;
  uiOptions.time_interval = uiOptions.selectedTime.time_interval;
  if (uiOptions.selectedTime && currentPrometheusServer.value) {
    stopTimeTick();
    loadMetrics();
    startTimeTick();
  }
};

const handleSelectRefreshInterval = async value => {
  refresh_interval.value = value;
  if (currentPrometheusServer.value && uiOptions.selectedTime) {
    stopTimeTick();
    loadMetrics();
    startTimeTick();
  }
};

const startTimeTick = () => {
  if (refresh_interval.value < 0 || !uiOptions.intervalId) {
    return;
  }

  uiOptions.intervalId = setInterval(() => {
    loadMetrics();
  }, refresh_interval.value);
};

const stopTimeTick = () => {
  if (uiOptions.intervalId) {
    clearInterval(uiOptions.intervalId);
    uiOptions.intervalId = null;
  }
};

const loadMetrics = async () => {
  if (!currentPrometheusServer.value) {
    return;
  }

  if (uiOptions.myChart) {
    uiOptions.myChart.showLoading({
      text: "loading",
      color: "#c23531",
      textColor: "#000",
      maskColor: "black",
      zlevel: 0
    });
  }

  const metricArgs = {
    cluster: props.cluster,
    namespace: currentPrometheusServer.value.namespace,
    service: currentPrometheusServer.value.service,
    prefix: currentPrometheusServer.value.prefix,
    service_port: currentPrometheusServer.value.service_port,
    namespace_name: props.yamlInfo.metadata.namespace,
    pod_name: props.yamlInfo.metadata.name,
    container_name: props.containerInfo.name
  };
  Promise.all([
    metric.getContainerMetricsMemAndFs(metricArgs),
    metric.getContainerMetricsCpu(metricArgs)
  ]).then(res => {
    if (uiOptions.myChart) {
      uiOptions.myChart.hideLoading();
    }
    initCharts(res);
  });
};

const initCharts = (res: [any, any]) => {
  if (!uiOptions.myChart) {
    uiOptions.myChart = echartInit(document.getElementById(uiOptions.chartId));
  }

  if (!res || res.length < 2) {
    return;
  }

  const [mem, cpu] = res;
  if (!mem.data.result || !mem.data.result[0] || !mem.data.result[0].values) {
    return;
  }
  if (!cpu.data.result || !cpu.data.result[0] || !cpu.data.result[0].values) {
    return;
  }

  const chartOption = {
    tooltip: {
      trigger: "axis"
    },
    legend: {
      data: ["Cpu", "Fs", "Mem"],
      textStyle: { color: "#FFF" }
    },
    xAxis: {
      type: "category",
      boundaryGap: false,
      data: arrayDuplicateRemovalSort(
        mem.data.result[0].values.map(its => {
          return moment(its[0] * 1000).format("YYYY-MM-DD HH:mm:ss");
        }),
        cpu.data.result.length > 0
          ? cpu.data.result[0].values.map(its => {
              return moment(its[0] * 1000).format("YYYY-MM-DD HH:mm:ss");
            })
          : []
      ),
      axisLabel: {
        interval: uiOptions.time_interval
      }
    },
    yAxis: [
      {
        type: "value",
        // splitLine: { show: false },
        axisLine: {
          show: true,
          lineStyle: {
            color: "#FFFFFF",
            width: 1,
            type: "solid"
          }
        },
        splitLine: {
          show: true,
          lineStyle: {
            color: "rgba(255,255,255,0.3)"
          }
        },
        name: "c", //单位
        nameLocation: "end" // (单位个也就是在在Y轴的最顶部)
      },
      {
        type: "value",
        // splitLine: { show: false },
        axisLine: {
          //y轴线的颜色以及宽度
          show: true,
          lineStyle: {
            color: "#FFFFFF",
            width: 1,
            type: "solid"
          }
        },

        splitLine: {
          show: true,
          lineStyle: {
            color: "rgba(255,255,255,0.3)"
          }
        },
        name: "MiB", //单位
        nameLocation: "end" // (单位个也就是在在Y轴的最顶部)
      },
      {
        type: "value",
        // splitLine: { show: false },
        axisLine: {
          //y轴线的颜色以及宽度
          show: true,
          lineStyle: {
            color: "#FFFFFF",
            width: 1,
            type: "solid"
          }
        },

        splitLine: {
          show: true,
          lineStyle: {
            color: "rgba(255,255,255,0.3)"
          }
        },
        name: "MiB", //单位
        nameLocation: "end" // (单位个也就是在在Y轴的最顶部)
      }
    ],
    series: [
      {
        name: "cpu",
        data:
          cpu.data.result.length > 0
            ? cpu.data.result[0].values.map(items => Number(items[1]))
            : [],
        type: "line",
        tooltip: {
          valueFormatter: function (value) {
            return value + " c";
          }
        }
      },
      {
        name: "fs",
        data: mem.data.result[0].values.map(
          items => Number(items[1]) / 1024.0 / 1024.0
        ),
        type: "line",
        tooltip: {
          valueFormatter: function (value) {
            return value + " MiB";
          }
        }
      },
      {
        name: "mem",
        data: mem.data.result[1].values.map(
          items => Number(items[1]) / 1024.0 / 1024.0
        ),
        type: "line",
        tooltip: {
          valueFormatter: function (value) {
            return value + " MiB";
          }
        }
      }
    ]
  };

  uiOptions.myChart.setOption(chartOption);
};

const reloadUI = async () => {
  await loadPrometheuses();
  loadMetrics();
  stopTimeTick();
  startTimeTick();
};

watch(
  () => props.cluster,
  (n, o) => {
    if (n !== o) {
      reloadUI();
    }
  },
  { deep: true }
);

watch(
  () => props.containerInfo,
  (n, o) => {
    reloadUI();
  }
);

onMounted(() => {
  reloadUI();
});

onUnmounted(() => {
  stopTimeTick();
});
</script>
